import static play.test.Helpers.fakeApplication;
import static play.test.Helpers.running;

import java.util.Date;

import models.Account;
import models.WmWallet;
import models.Account.ChineseProvince;
import models.Actor;
import models.Actor.EducationLevel;
import models.Actor.Honourific;
import models.Actor.HousingStatus;
import models.Actor.IdentityType;
import models.Actor.MaritalStatus;
import models.Addr.Ownership;
import models.Addr.YearsLived;
import models.Employment;
import models.Employment.CompanySegment;
import models.Employment.CompanySize;
import models.Employment.CompanyType;
import models.Employment.State;
import models.Employment.Status;
import models.Transaction.Type;
import models.LoanApp;

import org.junit.Test;

import prefix.integration.wm.AbstractWalletManager;
import prefix.integration.wm.WMException;
import prefix.integration.wm.WMProcessor;
import prefix.loan.util.LoanMaturity;
import prefix.platform.loan.LoanClass;
import prefix.transaction.TransactionTest;
import processor.AccountProcessor;
import processor.ActorProcessor;
import processor.AddrProcessor;
import processor.EmploymentProcessor;
import processor.LoanAppProcessor;
import processor.LoanProcessor;

import repository.LoanRepository;
import service.AccountService;
import service.ActorService;
import service.AddrService;
import service.EmploymentService;
import service.LoanAppService;
import service.LoanService;
import service.exception.AccountException;
import service.exception.ActorException;
import service.exception.EmploymentException;
import service.exception.LoanAppException;
import service.exception.LoanException;
import service.impl.AccountServiceImpl;
import service.impl.ActorServiceImpl;
import service.impl.AddrServiceImpl;
import service.impl.EmploymentServiceImpl;
import service.impl.LoanAppServiceImpl;
import service.impl.LoanServiceImpl;

public class LoanAppFlow {

    private final static String name = "刘德华";

    private final static String lender_name = "张学友";

    private final static Double income = 5500d;

    private final static String loanTitle = "我的贷款";

    private final static String loanDesc = "最好的贷款";

    private final static String homePhone = "0371-48252374";

    private final static String homePhoneExt = "0914";

    private final static String workPhone = "262-844-9969";

    private final static double loanAmount = 10000;

    private final static String loanPurpose = "credit_card";

    private final static String email = "lucas_" + Math.round(Math.random() * 100000000) + "@p2p.com";

    private final static String password = "welcome1";

    private final static String homeAddress = "高登金融大厦";

    private final static String city = "郑州";

    private final static String ip = "192.168.0.1";

    private final static String accountNumber = "41321412414212414";

    private final static String userName = "lucas_" + Math.round(Math.random() * 100000000);

    private final static String idNum = String.format("%19d", Math.round(Math.random() * 1000000000000000000l));

    private final static MaritalStatus marital = MaritalStatus.MARRIED;

    private final static Honourific honourific = Honourific.FEMALE;

    private final static IdentityType idType = IdentityType.ID_CARD;

    private final static HousingStatus houseStatus = HousingStatus.OWN;

    private final static EducationLevel edctnLvl = EducationLevel.MASTERS;

    private final static String homeStreet = "张江铁路一号";

    private final static String province = "河南";

    private final static String mobile = "13726452312";

    @Test
    public void startAppFlow() {
        running(fakeApplication(), new Runnable() {
            @Override
            public void run() {
                straightFlow();
            }
        });

    }

    private void straightFlow() {
        try {
            ActorService actor = this.createActor();
            this.updatePersonalInfo(actor, name);
            this.createWallet(actor.getDBActor().getId(), actor.getDBActor().getFullName());
            LoanAppService loanApp = this.createLoanApp(actor);
            AccountService account = this.addNewBankAccount(actor, ChineseProvince.Henan, city,
                    Account.FinancialInstitution.BC, accountNumber);
            this.submitContactInfo(actor);
            this.submitEmploymentInfo(actor);

            submitLoanApp(loanTitle, loanDesc, loanApp);

            LoanService loan = LoanRepository.getLoanByApp(loanApp.getDBLoanApp().getId());

            this.putLoanInfunding(loan);
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private void lenderFlow() {
        try {
            ActorService actor = this.createActor();
            this.updatePersonalInfo(actor, lender_name);
            this.createWallet(actor.getDBActor().getId(), actor.getDBActor().getFullName());
            AccountService account = this.addNewBankAccount(actor, ChineseProvince.Henan, city,
                    Account.FinancialInstitution.BC, accountNumber);
            this.submitContactInfo(actor);
            TransactionTest.transTest(Type.T0_ADD_FUNDS, actor.getDBActor().getId(), 6, actor.getDBActor().getId(),
                    null, null, 1500000);
        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private ActorService createActor() throws Throwable {
        ActorService service = new ActorServiceImpl();
        ActorProcessor processor = service.getProcessor();
        processor.createActor(email, password, mobile, Actor.TYPE.CUSTOMER);
        return service;
    }

    private void updatePersonalInfo(ActorService actor, String inputName) throws ActorException {
        ActorProcessor processor = actor.getProcessor();
        processor.updatePersonalInfo(userName, idNum, marital, honourific, idType, new Date(), houseStatus, edctnLvl,
                10000, inputName);
    }

    private void createWallet(Integer aid, String InputName) throws WMException {

        AbstractWalletManager.getInstance().createWallet(aid, InputName, WmWallet.Type.CUSTOMER);

    }

    private void submitContactInfo(ActorService actor) throws ActorException {
        AddrService addr = new AddrServiceImpl();
        AddrProcessor processor = addr.getProcessor();
        processor.submitContractInfo(actor.getDBActor().getId(), null, homeStreet, city, province, homePhone,
                YearsLived.FROM_4_TO_6, Ownership.OWN, homePhoneExt);

    }

    private void submitEmploymentInfo(ActorService actor) throws EmploymentException {
        EmploymentService empService = new EmploymentServiceImpl();
        EmploymentProcessor processor = empService.getProcessor();
        processor.saveEmploymentInfo(actor.getDBActor().getId(), Status.EMPLOYED, "CCTV", "COO", 12, homeAddress, city,
                "www.abc.com", province, CompanySegment.COMMUNICATION_ELECTRONICS, homePhone, homePhoneExt,
                CompanyType.EDUCATION, CompanySize.FROM_200_TO_299, new Date(), 0.32d, "cctv1", "cctv111", 31241d,
                312411d, 31231d, Employment.State.YES, State.YES, State.YES, State.YES);
    }

    private LoanAppService createLoanApp(ActorService actor) throws LoanAppException {
        LoanAppService service = new LoanAppServiceImpl();
        LoanAppProcessor processor = service.getProcessor();
        processor.createLoanApp(actor, LoanApp.LoanPurpose.SHOPPING, LoanApp.LoanType.PERSONAL, 10000d,
                LoanMaturity.Month3, LoanApp.PaymentMethod.AMORTIZATION);
        return service;
    }

    private void submitLoanApp(String title, String desc, LoanAppService loanApp) throws LoanAppException {
        LoanAppProcessor processor = loanApp.getProcessor();
        processor.submitLoanApp(title, desc);
    }

    private AccountService addNewBankAccount(ActorService actor, Account.ChineseProvince province, String city,
            Account.FinancialInstitution institution, String accountNumber) throws AccountException {
        AccountService service = new AccountServiceImpl();
        AccountProcessor processor = service.getProcessor();
        processor.addNewBankAccount(actor, province, city, institution, accountNumber);
        return service;
    }

    private void putLoanInfunding(LoanService loan) throws LoanException {
        LoanProcessor processor = loan.getProcessor();
        processor.assignLoanClass(LoanClass.B1, LoanMaturity.Month3);
        processor = loan.getProcessor();
        processor.putLoanInFunding();
    }

}
